package com.yanqu.road.server.gameplayer.module.kowloon;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.config.skill.SkillInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.kowloon.KowloonBuildingData;
import com.yanqu.road.entity.kowloon.KowloonHeroData;
import com.yanqu.road.entity.kowloon.KowloonUserData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleEnemyData;
import com.yanqu.road.entity.kowloon.battle.KowloonBattleHeroData;
import com.yanqu.road.entity.kowloon.common.KowloonRange;
import com.yanqu.road.entity.kowloon.common.Vec2;
import com.yanqu.road.entity.kowloon.config.KowloonBuildingConfig;
import com.yanqu.road.entity.kowloon.config.KowloonMissionRoadConfig;
import com.yanqu.road.entity.kowloon.config.KowloonNpcConfig;
import com.yanqu.road.entity.kowloon.enums.eKowloonBlockType;
import com.yanqu.road.entity.kowloon.enums.eKowloonNpcType;
import com.yanqu.road.entity.kowloon.enums.eKowloonOpType;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonBlock;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonChooseHeroData;
import com.yanqu.road.entity.kowloon.sanxiao.KowloonGameData;
import com.yanqu.road.entity.log.kowloon.*;
import com.yanqu.road.entity.log.kowloon.helper.LogBattleHeroData;
import com.yanqu.road.entity.log.kowloon.helper.LogMergeBlockData;
import com.yanqu.road.entity.servercenter.ServerInfo;
import com.yanqu.road.entity.task.args.KowloonHeroMergeArgs;
import com.yanqu.road.logic.bussiness.kowloon.KowloonBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.model.kowloon.KowloonConfig;
import com.yanqu.road.logic.model.kowloon.sanxiao.KowloonEliminateParam;
import com.yanqu.road.logic.model.kowloon.sanxiao.KowloonEliminateResult;
import com.yanqu.road.logic.model.kowloon.sanxiao.KowloonRoundResult;
import com.yanqu.road.logic.model.kowloon.sanxiao.KowloonShowResult;
import com.yanqu.road.pb.kowloon.KowloonProto;
import com.yanqu.road.pb.wineshop.WineShopProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.gameplayer.module.player.EarnSpeedModule;
import com.yanqu.road.server.manger.ServerListMgr;
import com.yanqu.road.server.manger.config.SkillMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.kowloon.KowloonEliminateLogic;
import com.yanqu.road.server.manger.kowloon.KowloonMgr;
import com.yanqu.road.server.manger.kowloon.battle.KowloonBattleLogic;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.rank.RankMgr;
import com.yanqu.road.server.pb.KowloonPb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.yanqu.road.logic.model.kowloon.KowloonConfig.DEFAULT_HERO_IDX_MAP;
import static com.yanqu.road.logic.model.kowloon.KowloonConfig.TILE_SIZE;

public class KowloonModule extends GeneralModule {

    /**
     * 用户数据
     */
    private KowloonUserData userData;

    /**
     * 建筑数据
     */
    private Map<Integer, KowloonBuildingData> buildingDataMap = new ConcurrentHashMap<>();

    /**
     * 好汉数据
     */
    private Map<Integer, KowloonHeroData> heroDataMap = new ConcurrentHashMap<>();

    private RandomHelper randomHelper = new RandomHelper();

    //调试用
    private LinkedList<KowloonGameData> historyGameDataList = new LinkedList<>();

    public KowloonModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        userData = KowloonBusiness.getKowloonUserData(player.getUserId());
        buildingDataMap = KowloonBusiness.getKowloonBuildingDataMap(player.getUserId());
        heroDataMap = KowloonBusiness.getKowloonHeroDataMap(player.getUserId());
        return true;
    }

    @Override
    public void loginSendMsg() {
        initSystem();
    }

    @Override
    public void afterLogin() {
        if (userData != null) {
            rankChange();
        }
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if (userData != null) {
            if (userData.isInsertOption()) {
                KowloonBusiness.addKowloonUserData(userData);
            } else if (userData.isUpdateOption()) {
                KowloonBusiness.updateKowloonUserData(userData);
            }
        }
        for (KowloonBuildingData buildingData : buildingDataMap.values()) {
            if (buildingData.isInsertOption()) {
                KowloonBusiness.addKowloonBuildingData(buildingData);
            } else if (buildingData.isUpdateOption()) {
                KowloonBusiness.updateKowloonBuildingData(buildingData);
            }
        }
        for (KowloonHeroData heroData : heroDataMap.values()) {
            if (heroData.isInsertOption()) {
                KowloonBusiness.addKowloonHeroData(heroData);
            } else if (heroData.isUpdateOption()) {
                KowloonBusiness.updateKowloonHeroData(heroData);
            }
        }
        return true;
    }

    /**
     * 初始化系统
     */
    public void initSystem() {
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if (serverInfo.getSpecialServer() != eSpecialServerType.Kowloon.getValue() && !SystemOpenMgr.systemOpen(player, eSystemId.Kowloon.getValue())) {
            return;
        }
        // 初始化用户信息
        initUserData();
        // 初始化建筑
        initBuildingData();
        // 初始化好汉
        initHeroData();

        // 初始化英雄位置信息
        int kowloonVersion = 1;
        if (player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.KowloonVersion) != kowloonVersion) {
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.KowloonVersion, kowloonVersion);
            // 初始化英雄的位置信息
            initHeroIdx();
        }

        // 计算下收益
        calcIncomeReward();

        // 更新下好汉信息
        updateHeroAttribute();

        // 修复引导代码
        int step = 1;
        if (!isFinishGuide(step) && userData.getGuideBit() > 1) {
            userData.setGuideBit(userData.getGuideBit() | (1 << (step - 1)));
        }

        // 同步数据
        syncUserData();
    }

    /**
     * 初始化英雄的位置信息
     */
    public void initHeroIdx() {
        for (KowloonHeroData heroData : heroDataMap.values()) {
            heroData.setHeroIdx(DEFAULT_HERO_IDX_MAP.getOrDefault(heroData.getHeroId(), -1));
        }
    }

    public Map<Integer, KowloonBuildingData> getBuildingDataMap() {
        return buildingDataMap;
    }

    public Map<Integer, KowloonHeroData> getHeroDataMap() {
        return heroDataMap;
    }

    /**
     * 初始化用户数据
     */
    private synchronized void initUserData() {
        if (userData == null) {
            userData = new KowloonUserData();
            userData.setUserId(player.getUserId());
            userData.setMoraleLevel(1);
            userData.setSpeedTimes(0);
            userData.setChapterId(0);
            userData.setIncomeReward("");
            userData.setLastGetRewardTime(System.currentTimeMillis());
            userData.setLastSettlementRewardTime(System.currentTimeMillis());
            userData.setUpdateTime(System.currentTimeMillis());
            userData.setChallengeTimes(0);
            userData.setChallengeResetTime(DateHelper.getTodayZeroTimeStamp());
            userData.setSpeedTimes(0);
            userData.setSpeedResetTime(DateHelper.getWeekBeginTimestamp());
            userData.setInsertOption();
        }
    }

    private void initHeroData() {
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return;
        }
        Map<Integer, Map<Integer, Map<Integer, KowloonNpcConfig>>> npcConfigMap = config.getNpcConfigMap().get(eKowloonNpcType.Hero);
        if (npcConfigMap == null) {
            return;
        }
        for (Map.Entry<Integer, Map<Integer, Map<Integer, KowloonNpcConfig>>> entry : npcConfigMap.entrySet()) {
            Integer heroId = entry.getKey();
            if (heroDataMap.containsKey(heroId)) {
                // 已存在
                continue;
            }
            // 获取等级为1的初始配置
            KowloonNpcConfig heroInitConfig = entry.getValue().get(1).get(1);
            if (heroInitConfig == null) {
                continue;
            }
            if (userData.getChapterId() < Integer.parseInt(heroInitConfig.getUnlockCond())) {
                // 不满足条件
                continue;
            }
            KowloonHeroData heroData = new KowloonHeroData();
            heroData.setUserId(player.getUserId());
            heroData.setHeroId(heroInitConfig.getNpcId());
            heroData.setLevel(heroInitConfig.getLevel());
            // 更新下属性
            updateHeroAttribute(heroData);
            heroData.setUpdateTime(System.currentTimeMillis());
            // 默认位置
            heroData.setHeroIdx(DEFAULT_HERO_IDX_MAP.getOrDefault(heroData.getHeroId(), -1));
            heroData.setInsertOption();
            heroDataMap.put(heroData.getHeroId(), heroData);
        }
    }

    private void initBuildingData() {
        // 暂无需初始化
    }

    private void addBuildingData(int buildingId) {
        KowloonBuildingData buildingData = new KowloonBuildingData();
        buildingData.setUserId(player.getUserId());
        buildingData.setBuildingId(buildingId);
        buildingData.setLevel(1);
        buildingData.setUpdateTime(System.currentTimeMillis());
        buildingData.setInsertOption();
        buildingDataMap.put(buildingData.getBuildingId(), buildingData);
    }


    public void syncUserData() {
        if (userData == null) {
            return;
        }
        KowloonProto.KowloonUserDataSyncMsg.Builder syncMsg = KowloonProto.KowloonUserDataSyncMsg.newBuilder();
        syncMsg.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
        for (KowloonBuildingData buildingData : buildingDataMap.values()) {
            syncMsg.addBuildingData(KowloonPb.parseKowloonBuildingDataTemp(buildingData));
        }
        for (KowloonHeroData heroData : getAllHeroList()) {
            syncMsg.addHeroData(KowloonPb.parseKowloonHeroDataTemp(heroData));
        }
        player.sendPacket(Protocol.U_KOWLOON_SYNC_USER_DATA, syncMsg);
    }

    /**
     * 获取用户数据
     */
    public int getUserDataByCmd() {
        if (userData == null) {
            return GameErrorCode.E_KOWLOON_USER_NOT_FOUND;
        }
        KowloonProto.KowloonUserDataRespMsg.Builder respMsg = KowloonProto.KowloonUserDataRespMsg.newBuilder();
        respMsg.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
        for (KowloonBuildingData buildingData : buildingDataMap.values()) {
            respMsg.addBuildingData(KowloonPb.parseKowloonBuildingDataTemp(buildingData));
        }
        for (KowloonHeroData heroData : getAllHeroList()) {
            respMsg.addHeroData(KowloonPb.parseKowloonHeroDataTemp(heroData));
        }
        respMsg.setRet(0);
        player.sendPacket(Protocol.U_KOWLOON_GET_USER_DATA, respMsg);
        return 0;
    }

    /**
     * 广告活动获取次数
     */
    public int addKowloonTime(int times){
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            log.error("KowloonConfig is null, ad reward failed");
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        //没解锁呢
        if (userData == null) {
            log.error("KowloonUserData is null, ad reward failed");
            return GameErrorCode.E_KOWLOON_USER_NOT_FOUND;
        }
        userData.setChallengeTimes(userData.getChallengeTimes() - times);
        syncUserData();
        return 0;
    }


    /**
     * 广告活动获取收益
     */
    public String getAdvertisementReward() {
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            log.error("KowloonConfig is null, ad reward failed");
            return "";
        }
        //没解锁呢
        if (userData == null) {
            log.error("KowloonUserData is null, ad reward failed");
            return "";
        }
        // 当前关卡挂机数据
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
        if (missionRoadConfig == null) {
            log.error("KowloonMissionRoadConfig is null, ad reward failed");
            return "";
        }

        // 领取收益
        calcIncomeReward();
        // 获得道具
        Property speedReward = PropertyHelper.parseStringToProperty(missionRoadConfig.getIncome());
        speedReward.goodCountMultiNum(GameConfig.KOWLOON_SINGLE_QUICK_GAIN_TIME_MAX);
        player.getModule(CurrencyModule.class).addCurrency(speedReward, eLogMoneyType.Kowloon, eLogMoneyType.KowloonSpeedIncomeRewardGet);
        String reward = PropertyHelper.parsePropertyToString(speedReward);

        return reward;
    }


    /**
     * 快速收益
     *
     * @param count 次数
     */
    public int speedIncomeReward(int count) {
        if (count < 0) {
            return GameErrorCode.E_KOWLOON_PARAM_ERROR;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        // 当前关卡挂机数据
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
        if (missionRoadConfig == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        // 领取收益
        calcIncomeReward();
        KowloonProto.KowloonSpeedIncomeRewardRespMsg.Builder respMsg = KowloonProto.KowloonSpeedIncomeRewardRespMsg.newBuilder();
        String reward = "";
        if (count == 0) {
            if (StringUtils.isNullOrEmpty(userData.getIncomeReward())) {
                return GameErrorCode.E_KOWLOON_NO_INCOME_REWARD;
            }
            reward = userData.getIncomeReward();
            userData.setIncomeReward("");
            long nowTime = System.currentTimeMillis();
            // 已超过上限
            if (nowTime - userData.getLastGetRewardTime() >= missionRoadConfig.getMaxTime() * DateHelper.HOUR_MILLIONS) {
                userData.setLastSettlementRewardTime(nowTime);
                userData.setLastGetRewardTime(nowTime);
            } else {
                // 记录为上一次结算时间
                userData.setLastGetRewardTime(userData.getLastSettlementRewardTime());
            }
            // 获得奖励
            player.getModule(CurrencyModule.class).addCurrency(PropertyHelper.parseStringToProperty(reward), eLogMoneyType.Kowloon, eLogMoneyType.KowloonGetIncomeRewardGet);
        } else {
            // 快速收益
            // 判断下本周次数上限
            if (userData.getSpeedTimes() + count > GameConfig.KOWLOON_WEEKLY_QUICK_GAIN_NUM_MAX) {
                return GameErrorCode.E_KOWLOON_SPEED_TIMES_LIMIT;
            }
            List<String> costList = StringUtils.stringToStringList(GameConfig.KOWLOON_SINGLE_QUICK_GAIN_COST, "\\|");
            // 消耗道具
            int speedTimes = userData.getSpeedTimes();
            Property cost = new Property();
            for (int i = 0; i < count; i++) {
                // 当前次数的消耗
                cost.addProperty(PropertyHelper.parseStringToProperty(costList.get(Math.min(costList.size() - 1, speedTimes))));
                speedTimes++;
            }
            if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.Kowloon, eLogMoneyType.KowloonSpeedIncomeRewardCost)) {
                return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
            }
            // 获得道具
            Property speedReward = PropertyHelper.parseStringToProperty(missionRoadConfig.getIncome());
            speedReward.goodCountMultiNum(count * GameConfig.KOWLOON_SINGLE_QUICK_GAIN_TIME_MAX);
            player.getModule(CurrencyModule.class).addCurrency(speedReward, eLogMoneyType.Kowloon, eLogMoneyType.KowloonSpeedIncomeRewardGet);
            reward = PropertyHelper.parsePropertyToString(speedReward);
            userData.setSpeedTimes(userData.getSpeedTimes() + count);
        }
        respMsg.setRet(0);
        respMsg.setReward(reward);
        respMsg.setIncomeReward(userData.getIncomeReward());
        respMsg.setLastGetRewardTime(userData.getLastGetRewardTime());
        respMsg.setLastSettlementRewardTime(userData.getLastSettlementRewardTime());
        respMsg.setSpeedTimes(userData.getSpeedTimes());
        player.sendPacket(Protocol.U_KOWLOON_SPEED_INCOME_REWARD, respMsg);
        return 0;
    }

    /** 领取挂机收益
     *
     * @return
     */
    public String getIncomeAward() {
        //先算
        calcIncomeReward();
        if (StringUtils.isNullOrEmpty(userData.getIncomeReward())) {
            return "";
        }
        String reward = "";
        reward = userData.getIncomeReward();
        userData.setIncomeReward("");
        long nowTime = System.currentTimeMillis();
        // 已超过上限
        KowloonConfig config = KowloonMgr.getConfig();
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
        if (nowTime - userData.getLastGetRewardTime() >= missionRoadConfig.getMaxTime() * DateHelper.HOUR_MILLIONS) {
            userData.setLastSettlementRewardTime(nowTime);
            userData.setLastGetRewardTime(nowTime);
        } else {
            // 记录为上一次结算时间
            userData.setLastGetRewardTime(userData.getLastSettlementRewardTime());
        }
        // 获得奖励
        player.getModule(CurrencyModule.class).addCurrency(PropertyHelper.parseStringToProperty(reward), eLogMoneyType.Kowloon, eLogMoneyType.KowloonGetIncomeRewardGet);
        syncUserData();

        return reward;
    }

    /**
     * 计算收益
     */
    private void calcIncomeReward() {
        if (userData == null) {
            return;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return;
        }
        // 当前关卡挂机数据
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
        if (missionRoadConfig == null) {
            return;
        }
        // 可收益时间
        long nowTime = System.currentTimeMillis();
        // 最大收益时间
        long maxRewardTime = missionRoadConfig.getMaxTime() * DateHelper.HOUR_MILLIONS + userData.getLastGetRewardTime();
        // 上次结算收益时间
        long lastSettlementRewardTime = userData.getLastSettlementRewardTime();
        // 可结算收益时间
        long minSettleTime = Math.min(nowTime, maxRewardTime);
        long settleMinute = (minSettleTime - lastSettlementRewardTime) / DateHelper.HOUR_MILLIONS;
        if (settleMinute > 0) {
            Property incomeReward = PropertyHelper.parseStringToProperty(userData.getIncomeReward());
            if (incomeReward == null) {
                incomeReward = new Property();
            }
            Property addIncomeReward = PropertyHelper.parseStringToProperty(missionRoadConfig.getIncome());
            addIncomeReward.goodCountMultiNum(settleMinute);
            incomeReward.addProperty(addIncomeReward);
            userData.setIncomeReward(PropertyHelper.parsePropertyToString(incomeReward));
            // 记录下结算时间
            userData.setLastSettlementRewardTime(userData.getLastSettlementRewardTime() + settleMinute * DateHelper.HOUR_MILLIONS);
        }
    }

    /**
     * 解锁/升级消耗
     *
     * @param buildingId 建筑id
     */
    public int upgradeBuilding(int buildingId) {
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        // 当前等级
        int curLevel = buildingDataMap.containsKey(buildingId) ? buildingDataMap.get(buildingId).getLevel() : 0;
        // 获取该建筑下级的配置
        KowloonBuildingConfig buildingConfig = config.getKowloonBuildingConfig(buildingId, curLevel + 1);
        if (buildingConfig == null) {
            return GameErrorCode.E_KOWLOON_BUILDING_CONFIG_NOT_FOUND;
        }
        // 解锁关卡
        if (userData.getChapterId() < buildingConfig.getNeedPassId()) {
            return GameErrorCode.E_KOWLOON_BUILDING_UNLOCK_NOT_ENOUGH;
        }
        // 判断消耗
        Property cost = PropertyHelper.parseStringToProperty(buildingConfig.getUnlockCost());
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.Kowloon, eLogMoneyType.KowloonUpgradeBuildingCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        // 解锁/升级建筑
        if (!buildingDataMap.containsKey(buildingId)) {
            addBuildingData(buildingId);
        } else {
            KowloonBuildingData buildingData = buildingDataMap.get(buildingId);
            buildingData.setLevel(buildingConfig.getLevel());
            buildingData.setUpdateTime(System.currentTimeMillis());
        }
        // 重新计算下繁荣值
        calcProsperousValue();
        //同步商铺赚速
        player.getModule(EarnSpeedModule.class).scheduleAddSilver();
        KowloonProto.KowloonUpgradeBuildingRespMsg.Builder respMsg = KowloonProto.KowloonUpgradeBuildingRespMsg.newBuilder();
        respMsg.setRet(0);
        for (KowloonBuildingData buildingData : buildingDataMap.values()) {
            respMsg.addBuildingData(KowloonPb.parseKowloonBuildingDataTemp(buildingData));
        }
        player.sendPacket(Protocol.U_KOWLOON_UPGRADE_BUILDING, respMsg);
        // 日志
        AutoLogMgr.add(new LogKowloonUpgradeBuilding(
                player.getUserId(),
                buildingId,
                curLevel,
                buildingDataMap.get(buildingId).getLevel()
        ));
        return 0;
    }

    /**
     * 升级建筑（同步升级）
     */
    public int upgradeBuilding() {

        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }

        KowloonProto.KowloonUpgradeBuildingOneKeyRespMsg.Builder clientMsg = KowloonProto.KowloonUpgradeBuildingOneKeyRespMsg.newBuilder();
        clientMsg.setRet(0);

        //计算所有消耗
        Property allCost = new Property();

        Map<Integer, Property> consumeList = new HashMap<>();

        for (Map.Entry<Integer, KowloonBuildingData> entry : buildingDataMap.entrySet()) {
            int buildingId = entry.getKey();
            KowloonBuildingData buildingData = entry.getValue();
            KowloonBuildingConfig buildingConfig = config.getKowloonBuildingConfig(buildingId, buildingData.getLevel() + 1);
            if(buildingConfig == null){
                continue;
            }
            Property cost = PropertyHelper.parseStringToProperty(buildingConfig.getUnlockCost());

            allCost.addProperty(cost);
            consumeList.put(buildingId, cost);
        }

        if(allCost.isNothing()){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        if (!player.getModule(CurrencyModule.class).removeCurrency(allCost, eLogMoneyType.Kowloon, eLogMoneyType.KowloonSyncUpgradeBuildingCost)) {
            clientMsg.setRet(GameErrorCode.E_BAG_ITEM_NO_ENOUGH);
            player.sendPacket(Protocol.U_KOWLOON_UPGRADE_BUILDING_ONE_KEY, clientMsg);
            return 0;
        }else {
            for (Map.Entry<Integer, Property> entry : consumeList.entrySet()) {
                int buildingId = entry.getKey();
                KowloonBuildingData buildingData = buildingDataMap.get(buildingId);

                // 日志
                AutoLogMgr.add(new LogKowloonUpgradeBuilding(
                        player.getUserId(),
                        buildingId,
                        buildingData.getLevel() - 1,
                        buildingData.getLevel()
                ));
                buildingData.setLevel(buildingData.getLevel() + 1);
                buildingData.setUpdateTime(System.currentTimeMillis());

                KowloonProto.KowloonBuildingDataTemp.Builder builder = KowloonPb.parseKowloonBuildingDataTemp(buildingData);
                clientMsg.addBuildingData(builder);
            }

            // 重新计算下繁荣值
            calcProsperousValue();
            //同步商铺赚速
            player.getModule(EarnSpeedModule.class).scheduleAddSilver();
            player.sendPacket(Protocol.U_KOWLOON_UPGRADE_BUILDING_ONE_KEY, clientMsg);
        }

        return 0;
    }


    public int upgradeHero(int heroId) {
        KowloonHeroData heroData = heroDataMap.get(heroId);
        if (heroData == null) {
            return GameErrorCode.E_KOWLOON_BUILDING_HERO_LOCK;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }

        int beforeLevel = heroData.getLevel();
        KowloonNpcConfig heroConfig = config.getKowloonHeroConfig(heroData.getHeroId(), heroData.getLevel());
        if (heroConfig == null) {
            return GameErrorCode.E_KOWLOON_BUILDING_HERO_CONFIG_NOT_FOUND;
        }
        if (userData.getChapterId() < Integer.parseInt(heroConfig.getUnlockCond())) {
            // 不满足条件
            return GameErrorCode.E_KOWLOON_BUILDING_HERO_CONFIG_NOT_FOUND;
        }
        // 获取下一级的配置
        KowloonNpcConfig nextHeroConfig = config.getKowloonHeroConfig(heroData.getHeroId(), heroData.getLevel() + 1);
        if (nextHeroConfig == null) {
            return GameErrorCode.E_KOWLOON_BUILDING_HERO_LEVEL_LIMIT;
        }
        // 判断消耗
        Property cost = PropertyHelper.parseStringToProperty(heroConfig.getUpCost());
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.Kowloon, eLogMoneyType.KowloonUpgradeHeroCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        heroData.setLevel(nextHeroConfig.getLevel());
        // 更新属性
        updateHeroAttribute(heroData);

        // 升级下上阵的好汉
        if (userData.getGameData() != null) {
            for (KowloonChooseHeroData chooseHeroData : userData.getGameData().getChooseHeroList()) {
                if (chooseHeroData.getHeroId() == heroId) {
                    chooseHeroData.setLevel(heroData.getLevel());
                    break;
                }
            }
        }

        KowloonProto.KowloonUpgradeHeroRespMsg.Builder respMsg = KowloonProto.KowloonUpgradeHeroRespMsg.newBuilder();
        respMsg.setRet(0);
        for (KowloonHeroData hero : getAllHeroList()) {
            respMsg.addHeroData(KowloonPb.parseKowloonHeroDataTemp(hero));
        }
        player.sendPacket(Protocol.U_KOWLOON_UPGRADE_HERO, respMsg);

        // 记录下日志
        AutoLogMgr.add(new LogKowloonUpgradeHero(
                player.getUserId(),
                heroId,
                beforeLevel,
                heroData.getLevel()
        ));
        return 0;
    }

    /**
     * 替换英雄
     * @param heroId
     * @param index
     * @return
     */
    public int replaceHero(int heroId, int index) {
        KowloonHeroData heroData = heroDataMap.get(heroId);
        if (heroData == null) {
            return GameErrorCode.E_KOWLOON_BUILDING_HERO_LOCK;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        if (index < 0 || index > 3) {
            return GameErrorCode.E_KOWLOON_PARAM_ERROR;
        }
        // 获取指定位置的好汉
        KowloonHeroData targetHero = getHeroByIndex(index);
        if (targetHero != null) {
            if (targetHero.getHeroId() == heroId) {
                return GameErrorCode.E_KOWLOON_PARAM_ERROR;
            }
            // 位置不为空，交换等级
            int targetHeroLevel = targetHero.getLevel();
            targetHero.setLevel(heroData.getLevel());
            heroData.setLevel(targetHeroLevel);

            // 交换位置
            int targetHeroIndex = targetHero.getHeroIdx();
            targetHero.setHeroIdx(heroData.getHeroIdx());
            heroData.setHeroIdx(targetHeroIndex);
        } else {
            // 位置为空，直接替换位置
            heroData.setHeroIdx(index);
        }
        // 更新下好汉数据
        updateHeroAttribute();

        // 同步数据
        KowloonProto.KowloonReplaceHeroRespMsg.Builder respMsg = KowloonProto.KowloonReplaceHeroRespMsg.newBuilder();
        respMsg.setRet(0);
        for (KowloonHeroData hero : getAllHeroList()) {
            respMsg.addHeroData(KowloonPb.parseKowloonHeroDataTemp(hero));
        }
        player.sendPacket(Protocol.U_KOWLOON_REPLACE_HERO, respMsg);
        return 0;
    }

    public KowloonHeroData getHeroByIndex(int index) {
        if (index < 0 || index > 3) {
            return null;
        }
        for (KowloonHeroData heroData : heroDataMap.values()) {
            if (heroData.getHeroIdx() == index) {
                return heroData;
            }
        }
        return null;
    }

    /**
     * 重新计算下繁荣值
     */
    private void calcProsperousValue() {
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return;
        }
        long totalProsperousValue = 0;
        for (KowloonBuildingData buildingData : buildingDataMap.values()) {
            KowloonBuildingConfig buildingConfig = config.getKowloonBuildingConfig(buildingData.getBuildingId(), buildingData.getLevel());
            if (buildingConfig != null) {
                totalProsperousValue += buildingConfig.getProsperousValue();
            }
        }
        userData.setProsperousValue(totalProsperousValue);
        KowloonProto.KowloonProsperousSyncMsg.Builder syncMsg = KowloonProto.KowloonProsperousSyncMsg.newBuilder();
        syncMsg.setProsperousValue(totalProsperousValue);
        player.sendPacket(Protocol.U_KOWLOON_SYNC_PROSPEROUS, syncMsg);
        // 更新下榜单
        rankChange();
    }

    private void rankChange() {
        if (this.getUserData().getProsperousValue() > 0) {
            RankMgr.changeUserRank(eBigRankType.Normal.getValue(), player.getUserId(), BigInteger.valueOf(this.getUserData().getProsperousValue()), eRankType.KowloonProsperousValue.getValue(), String.valueOf(this.userData.getChapterId()));
        }
    }

    /**
     * 升级士气
     */
    public int upgradeMorale(boolean isBroken) {
        if (userData == null) {
            return GameErrorCode.E_KOWLOON_USER_NOT_FOUND;
        }
        int beforeLevel = userData.getMoraleLevel();
        // 获取当前士气等级
        int moraleSkillId = KowloonMgr.getKowloonMoraleSkillId(userData.getMoraleLevel());
        if (moraleSkillId == 0) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        // 获取下一级的士气等级
        SkillInfo nextSkillInfo = KowloonMgr.getKowloonMoraleSkillInfo(userData.getMoraleLevel() + 1);
        if (nextSkillInfo == null) {
            return GameErrorCode.E_KOWLOON_MORALE_LEVEL_LIMIT;
        }
        List<Integer> paramList = nextSkillInfo.getParamList();
        if (isBroken) {
            if (userData.isMoraleBroken()) {
                return GameErrorCode.E_KOWLOON_MORALE_ALREADY_BROKEN;
            }
            if (paramList.get(1) == 0) {
                return GameErrorCode.E_KOWLOON_NO_NEED_BROKEN;
            }
            // 判断是否达到突破条件
            if (userData.getChapterId() < paramList.get(1)) {
                return GameErrorCode.E_KOWLOON_MORALE_DONT_BROKEN;
            }
            userData.setMoraleBroken(true);
        } else {
            // 判断需不需要突破
            if (paramList.get(1) != 0 && !userData.isMoraleBroken()) {
                return GameErrorCode.E_KOWLOON_MORALE_NEED_BROKEN;
            }
            if (player.getTitleId() < paramList.get(2)) {
                return GameErrorCode.E_KOWLOON_MORALE_DONT_UPGRADE;
            }
            userData.setMoraleLevel(userData.getMoraleLevel() + 1);
            userData.setMoraleBroken(false);
        }
        // 更新下好汉属性
        updateHeroAttribute();
        KowloonProto.KowloonUpgradeMoraleRespMsg.Builder respMsg = KowloonProto.KowloonUpgradeMoraleRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setMoraleLevel(userData.getMoraleLevel());
        respMsg.setMoraleBroken(userData.isMoraleBroken());
        for (KowloonHeroData hero : getAllHeroList()) {
            respMsg.addHeroData(KowloonPb.parseKowloonHeroDataTemp(hero));
        }
        player.sendPacket(Protocol.U_KOWLOON_UPGRADE_MORALE, respMsg);

        // 记录下日志
        AutoLogMgr.add(new LogKowloonUpgradeMorale(
                player.getUserId(),
                beforeLevel,
                userData.getMoraleLevel(),
                isBroken
        ));
        return 0;
    }

    /**
     * 结束引导
     * 1:开局动画以及剧情对话1（100500-100504）
     * 2:挑战第一关直到弹出战斗胜利（100505-100506）
     * 3:剧情对话2（100507-100512）
     * 4:领取挂机收益（100513-100515）
     * 5:升级好汉（100516-100520）
     * 6:收购建筑（100521-100524）
     * 7:升级建筑（100525-100526）
     * 8:自由行动（100527-100532）
     * 9:挑战第二关直到弹出战斗失败（100533-100534）
     * 10：玩家重回九龙并士气等级<2级 点击挑战（仅引导一次）
     * 11：玩家重回九龙并士气等级>=2级 点击挑战（仅引导一次）
     * 12：玩家重回九龙并挑战第2关失败（仅引导一次）
     * 13：玩家重回九龙并挑战第2关胜利（仅引导一次）
     * 14：是否在引导后重命名
     * 21:第一关局内引导（100600-100604）
     * 22:第三关局内引导（100606-100607）
     */
    public int finishGuide(List<Integer> steps) {
        if (userData == null) {
            return GameErrorCode.E_KOWLOON_USER_NOT_FOUND;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        KowloonProto.KowloonFinishGuideRespMsg.Builder respMsg = KowloonProto.KowloonFinishGuideRespMsg.newBuilder();
        respMsg.setRet(0);
        Property guideReward = new Property();
        for (Integer step : steps) {
            if (isFinishGuide(step)) {
                continue;
            }
            // 判断是否有奖励
            if (step == 4) {
                // 获取挂机收益
                KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(config.getInitChapterId());
                if (missionRoadConfig != null) {
                    Property property = PropertyHelper.parseStringToProperty(missionRoadConfig.getIncome());
                    property.goodCountMultiNum(GameConfig.KOWLOON_GUIDE_FREE_TIME);
                    guideReward.addProperty(property);
                }
            }
            // 记录引导
            userData.setGuideBit(userData.getGuideBit() | (1 << (step - 1)));
        }
        if (!guideReward.isNothing()) {
            player.getModule(CurrencyModule.class).addCurrency(guideReward, eLogMoneyType.Kowloon, eLogMoneyType.KowloonFinishGuideReward);
            respMsg.setReward(PropertyHelper.parsePropertyToString(guideReward));
        }
        respMsg.setGuideBit(userData.getGuideBit());
        player.sendPacket(ClientProtocol.U_KOWLOON_FINISH_GUIDE, respMsg);
        return 0;
    }


    /**
     * 是否完成引导
     */
    public boolean isFinishGuide(int step) {
        if (userData == null) {
            return false;
        }
        return ((userData.getGuideBit() >> (step - 1) & 1) == 1);
    }

    /**
     * 更新好汉属性
     */
    public void updateHeroAttribute() {
        for (KowloonHeroData heroData : heroDataMap.values()) {
            updateHeroAttribute(heroData);
        }
    }

    /**
     * 获取所有的好汉列表
     * ！！！客户端强制要的，未解锁的好汉也需计算下发
     */
    public List<KowloonHeroData> getAllHeroList() {
        List<KowloonHeroData> heroList = new ArrayList<>();
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return heroList;
        }
        // 已解锁的好汉
        heroList.addAll(heroDataMap.values());

        // 未解锁的好汉也需要数据
        Map<Integer, Map<Integer, Map<Integer, KowloonNpcConfig>>> npcConfigMap = config.getNpcConfigMap().get(eKowloonNpcType.Hero);
        for (Map.Entry<Integer, Map<Integer, Map<Integer, KowloonNpcConfig>>> entry : npcConfigMap.entrySet()) {
            Integer heroId = entry.getKey();
            if (!heroDataMap.containsKey(heroId)) {
                // 不存在的好汉也要计算数据
                KowloonHeroData heroData = new KowloonHeroData();
                heroData.setUserId(player.getUserId());
                heroData.setHeroId(heroId);
                heroData.setLevel(1);
                heroData.setHeroIdx(-1);
                heroData.setUpdateTime(System.currentTimeMillis());
                // 计算下属性
                updateHeroAttribute(heroData);

                // 未解锁的等级改为0
                heroData.setLevel(0);
                heroList.add(heroData);
            }
        }
        return heroList;
    }

    /**
     * 更新好汉属性
     */
    public void updateHeroAttribute(KowloonHeroData heroData) {
        if (userData == null || heroData == null) {
            return;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return;
        }
        KowloonNpcConfig heroConfig = config.getKowloonHeroConfig(heroData.getHeroId(), heroData.getLevel());
        if (heroConfig == null) {
            return;
        }
        // 基础属性
        heroData.setAttributeData(config.calcHeroAttribute(heroData.getHeroId(), heroData.getLevel()));
        // 攻击力士气加成
        long addition = 0;
        // 获取当前士气技能
        SkillInfo moraleSkillInfo = KowloonMgr.getKowloonMoraleSkillInfo(userData.getMoraleLevel());
        if (moraleSkillInfo != null) {
            List<Integer> paramList = moraleSkillInfo.getParamList();
            addition += paramList.get(3);
        }
        heroData.getAttributeData().setAttack(BigDecimal.valueOf(heroData.getAttributeData().getAttack()).multiply(BigDecimal.valueOf(1000 + addition)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue());
    }

    /**
     * 进入关卡
     */
    public int enterChapter(int chapterId, List<Integer> heroIdList) {
        if (userData == null) {
            return GameErrorCode.E_KOWLOON_USER_NOT_FOUND;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (null == config) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(chapterId, config.getInitSectionId());
        if (null == missionRoadConfig) {
            return GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND;
        }
        KowloonProto.KowloonEnterChapterRespMsg.Builder respMsg = KowloonProto.KowloonEnterChapterRespMsg.newBuilder();
        // 【继续游戏】
        if (userData.getGameData() == null) {
            // 开启新游戏
            if (userData.getChallengeTimes() >= GameConfig.KOWLOON_DAILY_CHALLENGE_TIMES) {
                return GameErrorCode.E_KOWLOON_CHALLENGE_TIMES_LIMIT;
            }
            KowloonGameData gameData = new KowloonGameData();
            KowloonProto.KowloonGameDataMsg.Builder guideDataMsg = KowloonMgr.getGuideDataMsg(missionRoadConfig.getMissionRoadId());
            boolean isFinishGuide = false;
            if (missionRoadConfig.getMissionRoadId() == config.getFirstGuideMissionRoadId()) {
                isFinishGuide = isFinishGuide(21);
            } else if (missionRoadConfig.getMissionRoadId() == config.getSecondGuideMissionRoadId()) {
                isFinishGuide = isFinishGuide(22);
            }
            if (null != guideDataMsg && !isFinishGuide) { //有引导数据的都跑引导
                respMsg.setGameData(guideDataMsg);
                gameData = KowloonMgr.cloneGuideGameData(missionRoadConfig.getMissionRoadId());

                ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
                if (serverInfo.getSpecialServer() != eSpecialServerType.Kowloon.getValue()) {
                    if (missionRoadConfig.getMissionRoadId() == config.getFirstGuideMissionRoadId()) {
                        finishGuide(Collections.singletonList(21));
                    } else if (missionRoadConfig.getMissionRoadId() == config.getSecondGuideMissionRoadId()) {
                        finishGuide(Collections.singletonList(22));
                    }
                }
            } else {
                gameData.setMaxHp(GameConfig.KOWLOON_BOOTH_HP); //这里到时候根据配置获得进场血量
                gameData.setHp(gameData.getMaxHp());
                gameData.setChapterId(chapterId);
                gameData.setSectionId(missionRoadConfig.getWave());
                gameData.setLeftStep(missionRoadConfig.getStepNum());
                gameData.setBeginTime(DateHelper.getCurrentTime());
                // 上阵好汉
                List<KowloonChooseHeroData> chooseHeroDataList = new ArrayList<>();
                // 添加上阵好汉
                for (Integer heroId : heroDataMap.keySet()) {
                    if (chooseHeroDataList.size() >= KowloonConfig.BATTLE_HERO_COUNT) {
                        break;
                    }
                    KowloonHeroData heroData = getHeroData(heroId);
                    if (heroData == null || heroData.getHeroIdx() == -1) {
                        continue;
                    }
                    chooseHeroDataList.add(new KowloonChooseHeroData(heroId, heroData.getLevel(), heroData.getHeroIdx()));
                }
                // 根据index排个序
                chooseHeroDataList.sort(Comparator.comparingInt(KowloonChooseHeroData::getIndex));
                gameData.setChooseHeroList(chooseHeroDataList);

                KowloonEliminateParam param = new KowloonEliminateParam();
                param.setConfig(KowloonMgr.getConfig());
                param.setGameData(gameData);

                gameData.setBlockList(KowloonEliminateLogic.getBlockListByConfig(param, config, chapterId));
//                gameData.setBlockList(KowloonEliminateLogic.getTestListList());

                // 生成的盘面
                KowloonProto.KowloonGameDataMsg.Builder beforeMove = KowloonPb.parseKowloonGameDataMsg(gameData);
                KowloonEliminateResult kowloonEliminateResult = KowloonEliminateLogic.moveBlock(param);
                List<KowloonProto.KowloonShowMsg> showMsgs = KowloonPb.parseShowListMsg(kowloonEliminateResult.getShowResultList());
                KowloonProto.KowloonGameDataMsg.Builder afterMove = KowloonPb.parseKowloonGameDataMsg(param.getGameData());
                KowloonProto.KowloonOperateRespMsg.Builder showDataMsg = KowloonProto.KowloonOperateRespMsg.newBuilder();
                showDataMsg.setRet(0);
                showDataMsg.setGameData(afterMove);
                showDataMsg.addAllShow(showMsgs);
                beforeMove.setShowData(showDataMsg);
                respMsg.setGameData(beforeMove);
            }

            userData.setChallengeTimes(userData.getChallengeTimes() + 1);

            userData.setGameData(gameData);
            // 检查boss预警
            checkBossCol();
//            historyGameDataList.clear();
//            if (gameData != null) {
//                historyGameDataList.addLast(gameData.clone());
//            }
        } else {
            // 检测下战斗
            KowloonProto.KowloonGameDataMsg.Builder battle = battle();
            if (battle != null) {
                respMsg.setGameData(battle);
            } else {
                respMsg.setGameData(KowloonPb.parseKowloonGameDataMsg(userData.getGameData()));
            }
        }
        respMsg.setRet(0);
        respMsg.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
        player.sendPacket(ClientProtocol.U_KOWLOON_ENTER_CHAPTER, respMsg);

        if (userData.getGameData() != null) {
            notifyHeroCondition(userData.getGameData());
        }
        return 0;
    }

    private void notifyHeroCondition(KowloonGameData gameData) {
        for (List<KowloonBlock> kowloonBlocks : gameData.getBlockList()) {
            for (KowloonBlock block : kowloonBlocks) {
                if (eKowloonBlockType.isHero(block.getType())) {
                    // 英雄
                    int heroId = block.getType();
                    // 成就
                    player.notifyListener(eGamePlayerEventType.KowLoonHeroMerge.getValue(), new KowloonHeroMergeArgs(heroId, block.getLevel()));
                }
            }
        }
    }

    public KowloonUserData getUserData() {
        return userData;
    }

    public KowloonHeroData getHeroData(int heroId) {
        return heroDataMap.get(heroId);
    }

    /**
     * 操作
     */
    public KowloonProto.KowloonOperateRespMsg.Builder operate(KowloonProto.KowloonOperateReqMsg reqMsg) {
        KowloonProto.KowloonOperateRespMsg.Builder respMsg = KowloonProto.KowloonOperateRespMsg.newBuilder();
        respMsg.setRet(0);
        if (userData == null) {
            return respMsg.setRet(GameErrorCode.E_KOWLOON_USER_NOT_FOUND);
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return respMsg.setRet(GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND);
        }

        if (userData.getGameData() == null) {
            return respMsg.setRet(GameErrorCode.E_ERROR_DATA);
        }

        if (reqMsg.getType() == eKowloonOpType.MoveOut.getValue() || reqMsg.getType() == eKowloonOpType.Destroy.getValue()) {
            // 判断下是否解锁
            if (userData.getChapterId() < GameConfig.KOWLOON_MOVEOUT_AND_DESTROY_UNLOCK) {
                return respMsg.setRet(GameErrorCode.E_KOWLOON_OPERATE_LOCK);
            }
        }

        //返回上一步,调试用,记得屏蔽
//        if (reqMsg.getType() == eKowloonOpType.BackStep.getValue()){
//            KowloonGameData gameData = historyGameDataList.removeLast();
//            userData.setGameData(gameData);
//            respMsg.setGameData(KowloonPb.parseKowloonGameDataMsg(userData.getGameData()));
//            return respMsg.setRet(0);
//        }

        // 战斗表现结束
        if (reqMsg.getType() == eKowloonOpType.Battle.getValue()) {
            respMsg.setGameData(KowloonPb.parseKowloonGameDataMsg(userData.getGameData()));
            return respMsg.setRet(0);
        }

        if (userData.getGameData().getShowNo() != reqMsg.getShowNo()) {
            respMsg.setGameData(KowloonPb.parseKowloonGameDataMsg(userData.getGameData()));
            return respMsg.setRet(GameErrorCode.E_ERROR_DATA);
        }

        if (userData.getGameData().getLeftStep() <= 0 && reqMsg.getType() != eKowloonOpType.ChoseSkill.getValue()) {
            // 做个容错，检测下战斗
            KowloonProto.KowloonGameDataMsg.Builder battle = battle();
            if (battle != null) {
                respMsg.setGameData(battle);
            }
            return respMsg.setRet(GameErrorCode.E_KOWLOON_STEP_NOT_ENOUGH);
        }

        KowloonEliminateParam param = new KowloonEliminateParam();
        param.setConfig(config);
        param.setGameData(userData.getGameData().clone()); //复制盘面
        param.setFromX(reqMsg.getFromX());
        param.setFromY(reqMsg.getFromY());
        param.setToX(reqMsg.getToX());
        param.setToY(reqMsg.getToY());
        param.setType(reqMsg.getType());
        param.setFirstMove(true);
        param.setKowloonSkillInfoMap(SkillMgr.getKowloonSkillInfoMap());

        KowloonEliminateResult kowloonEliminateResult = KowloonEliminateLogic.moveBlock(param);
        if (kowloonEliminateResult.getRet() != 0) {
            return respMsg.setRet(kowloonEliminateResult.getRet());
        }

        //更新步数
        //选技能不扣步数
        if (reqMsg.getType() != eKowloonOpType.ChoseSkill.getValue()) {
            param.getGameData().setUseStep(param.getGameData().getUseStep() + 1);
            param.getGameData().setLeftStep(param.getGameData().getLeftStep() - 1);
        }

        //更新表现参数
        param.getGameData().setShowNo(reqMsg.getShowNo() + 1);

        //更新盘面到玩家身上
        userData.setGameData(param.getGameData());


        List<LogMergeBlockData> logMergeHeroList = new ArrayList<>();
        List<LogMergeBlockData> logMergeSkillList = new ArrayList<>();
        for (KowloonShowResult kowloonShowResult : kowloonEliminateResult.getShowResultList()) {
            for (KowloonRoundResult roundResult : kowloonShowResult.getRoundResults()) {
                List<KowloonBlock> createBlockList = roundResult.getCreateBlock();
                for (KowloonBlock block : createBlockList) {
                    LogMergeBlockData logMergeBlockData = new LogMergeBlockData();
                    logMergeBlockData.setLevel(block.getLevel());
                    logMergeBlockData.setX(block.getX());
                    logMergeBlockData.setY(block.getY());
                    if (eKowloonBlockType.isHero(block.getType())) {
                        // 英雄
                        int heroId = block.getType();
                        logMergeBlockData.setBlockId(heroId);
                        logMergeHeroList.add(logMergeBlockData);
                    } else {
                        logMergeBlockData.setBlockId(block.getType());
                        logMergeSkillList.add(logMergeBlockData);
                    }
                }
            }
        }

        if (userData.getGameData() != null) {
            notifyHeroCondition(userData.getGameData());
        }

        // 记录下日志
        AutoLogMgr.add(new LogKowloonMerge(
                player.getUserId(),
                userData.getGameData().getChapterId(),
                userData.getGameData().getSectionId(),
                reqMsg.getType(),
                JSON.toJSONString(new ArrayList<>(Arrays.asList(reqMsg.getFromX(), reqMsg.getFromY(), reqMsg.getToX(), reqMsg.getToY()))),
                kowloonEliminateResult.getEliminateAmount(),
                reqMsg.getFromX(),
                JSON.toJSONString(logMergeHeroList),
                JSON.toJSONString(logMergeSkillList),
                JSON.toJSONString(userData.getGameData().getSkillList()),
                kowloonEliminateResult.getSkillAddStep(),
                kowloonEliminateResult.getEliminateAddStep(),
                userData.getGameData().getUseStep(),
                userData.getGameData().getLeftStep()
        ));
//
//        log.info("剩余步数{}", userData.getGameData().getLeftStep());
//        log.info("使用步数{}", userData.getGameData().getUseStep());

        // 检测战斗
        KowloonProto.KowloonGameDataMsg.Builder battle = battle();
        if (battle != null) {
            respMsg.setGameData(battle);
        } else {
            respMsg.setGameData(KowloonPb.parseKowloonGameDataMsg(userData.getGameData()));
        }
        respMsg.addAllShow(KowloonPb.parseShowListMsg(kowloonEliminateResult.getShowResultList()));
//        if (userData.getGameData() != null) {
//            historyGameDataList.addLast(userData.getGameData().clone());
//        }

        return respMsg;
    }


    /**
     * 检测战斗
     */
    public KowloonProto.KowloonGameDataMsg.Builder battle() {
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null || userData.getGameData() == null) {
            return null;
        }
        // 剩余步数为0且身上有没有技能
        if (userData.getGameData().getLeftStep() > 0 || !userData.getGameData().getChooseSkill().isEmpty()) {
            return null;
        }
        // 战斗 拷贝一份战斗前数据
        KowloonGameData gameDataClone = userData.getGameData().clone();
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        KowloonBattleData battle = new KowloonBattleLogic(userData, serverInfo, KowloonMgr.getKowloonMoraleSkillInfo(userData.getMoraleLevel()), config)
                .battle();

        // 记录日志
        // 敌人信息
        Map<Integer, Integer> hurtMap = new HashMap<>();
        for (KowloonBattleEnemyData enemyData : battle.getEnemyDataList()) {
            hurtMap.put(enemyData.getEnemyId(), hurtMap.getOrDefault(enemyData.getEnemyId(), 0) + enemyData.getDamage());
        }

        // 好汉信息
        List<LogBattleHeroData> logBattleHeroDataList = new ArrayList<>();
        for (KowloonBattleHeroData heroData : battle.getHeroDataList()) {
            LogBattleHeroData logBattleHeroData = new LogBattleHeroData();
            logBattleHeroData.setHeroId(heroData.getHeroId());
            logBattleHeroData.setLevel(heroData.getMergeLevel());
            logBattleHeroData.setAttack(heroData.getProperty().getAttack());
            logBattleHeroData.setX(heroData.getPos().getCol());
            logBattleHeroData.setY(heroData.getPos().getRow());
            logBattleHeroDataList.add(logBattleHeroData);
        }
        int chapterId = userData.getGameData().getChapterId();
        int sectionId = userData.getGameData().getSectionId();
        AutoLogMgr.add(new LogKowloonBattle(
                player.getUserId(),
                chapterId,
                sectionId,
                JSON.toJSONString(hurtMap),
                JSON.toJSONString(logBattleHeroDataList),
                gameDataClone.getMaxHp(),
                userData.getGameData().getHp(),
                JSON.toJSONString(gameDataClone.getSkillList()),
                userData.getMoraleLevel()
        ));

        // 处理结果
        boolean isFinish = false;
        String onceReward = "";
        if (battle.isWin()) {
            KowloonMissionRoadConfig nextWaveMissionRoadConfig = config.getKowloonMissionRoadConfig(userData.getGameData().getChapterId(), userData.getGameData().getSectionId() + 1);
            if (nextWaveMissionRoadConfig == null) {
//                // 没有下一波记为通关
//                if (userData.getGameData().getChapterId() > userData.getChapterId()) {
//                    userData.setChapterId(userData.getGameData().getChapterId());
//                    // 当前关卡记为通关
//                    notifyChapterCondition();
//                    // 获取当前关的信息
//                    KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
//                    if (missionRoadConfig != null) {
//                        // 获得道具
//                        onceReward = missionRoadConfig.getOnceReward();
//                        Property property = new Property();
//                        if (!StringUtils.isNullOrEmpty(onceReward)) {
//                            property.addProperty(PropertyHelper.parseStringToProperty(onceReward));
//                        }
//                        // 特色服特殊处理,第一关通关发更改形象卡
//                        if (serverInfo.getSpecialServer() == 1 && userData.getChapterId() == config.getInitChapterId()) {
//                            property.addProperty(new Property(110268, 1));
//                        }
//                        if (!property.isNothing()) {
//                            player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Kowloon, eLogMoneyType.KowloonChapterOnceReward);
//                        }
//                    }
//                }
//                // 清空gameData
//                userData.setGameData(null);
//                // 第一次通关要处理下，开始收益
//                if (userData.getChapterId() == config.getInitChapterId()) {
//                    long nowTime = System.currentTimeMillis();
//                    userData.setLastGetRewardTime(nowTime);
//                    userData.setLastSettlementRewardTime(nowTime);
//                }
                //过关处理
                onceReward = this.passHandle(userData.getGameData().getChapterId());
                isFinish = true;
            } else {
                // 下一波
                userData.getGameData().setSectionId(nextWaveMissionRoadConfig.getWave());
                userData.getGameData().setLeftStep(nextWaveMissionRoadConfig.getStepNum());
                // 检测boss预警路线
                checkBossCol();
            }
        } else {
            // 战斗失败
            userData.setGameData(null);
            isFinish = true;
        }

        if (isFinish) {
            // 记录结算日志
            AutoLogMgr.add(new LogKowloonChapterFinish(player.getUserId(), chapterId, battle.isWin() ? 1 : 0));
        }

        KowloonProto.KowloonResultMsg.Builder result = null;
        if (isFinish) {
            // 战斗结果
            result = KowloonProto.KowloonResultMsg.newBuilder();
            result.setChapterId(gameDataClone.getChapterId());
            result.setSectionId(gameDataClone.getSectionId());
            result.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
            result.setIsWin(battle.isWin());
            result.setReward(onceReward);
        }
        return KowloonPb.parseKowloonGameDataMsg(gameDataClone, battle, result);
    }

    /**
     * 过关处理
     * @param chapterId 当前关卡
     * @return
     */
    private String passHandle(int chapterId) {
        //配置
        KowloonConfig config = KowloonMgr.getConfig();
        //奖励
        String onceReward = "";
        // 没有下一波记为通关
        if (chapterId > this.userData.getChapterId()) {
            userData.setChapterId(chapterId);
            // 当前关卡记为通关
            notifyChapterCondition();
            // 获取当前关的信息
            KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getChapterId());
            if (missionRoadConfig != null) {
                // 获得道具
                onceReward = missionRoadConfig.getOnceReward();
                Property property = new Property();
                if (!StringUtils.isNullOrEmpty(onceReward)) {
                    property.addProperty(PropertyHelper.parseStringToProperty(onceReward));
                }
                // 特色服特殊处理,第一关通关发更改形象卡
                ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
                if (serverInfo.getSpecialServer() == eSpecialServerType.Kowloon.getValue() && userData.getChapterId() == config.getInitChapterId()) {
                    property.addProperty(new Property(110268, 1));
                }
                if (!property.isNothing()) {
                    player.getModule(CurrencyModule.class).addCurrency(property, eLogMoneyType.Kowloon, eLogMoneyType.KowloonChapterOnceReward);
                }
            }
        }
        // 清空gameData
        userData.setGameData(null);
        // 第一次通关要处理下，开始收益
        if (userData.getChapterId() == config.getInitChapterId()) {
            long nowTime = System.currentTimeMillis();
            userData.setLastGetRewardTime(nowTime);
            userData.setLastSettlementRewardTime(nowTime);
        }
        // 更新下榜单
        rankChange();
        return onceReward;
    }

    public void notifyChapterCondition() {
        // 当前已通关的关卡
        player.notifyListener(eGamePlayerEventType.KowloonChapter297.getValue(), userData.getChapterId());
        player.notifyListener(eGamePlayerEventType.KowloonChapter298.getValue(), userData.getChapterId());

        // 检测一下好汉解锁情况
        initHeroData();
        // 更新下好汉信息
        updateHeroAttribute();
        // 同步数据
//        syncUserData();
    }

    /**
     * 检测boss预警路线
     */
    public void checkBossCol() {
        if (userData.getGameData() == null) {
            return;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        if (config == null) {
            return;
        }
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(userData.getGameData().getChapterId(), userData.getGameData().getSectionId());
        if (missionRoadConfig == null) {
            return;
        }
        // 检查有没有boss
        boolean existBoss = false;
        List<Integer> allBossCol = new ArrayList<>();
        for (int i = 0; i < missionRoadConfig.getRuffianIdList().size(); i++) {
            Integer bossId = missionRoadConfig.getRuffianIdList().get(i);
            KowloonNpcConfig bossConfig = config.getKowloonBossConfig(bossId);
            if (bossConfig == null) {
                continue;
            }
            existBoss = true;
            // boss受击范围
            KowloonRange hitRange = bossConfig.getNpcAttribute().getHitRange();
            // 生成数量
            Integer genCount = missionRoadConfig.getRuffianNum().get(i);
            // 行走路线
            String walkRoute = missionRoadConfig.getRuffianWalkRoute().get(i);
            String[] split = walkRoute.split("=");
            int yPos = Integer.parseInt(split[0]);
            for (int j = 0; j < genCount; j++) {
                // boss idx在1~4随机
                int randomX = randomHelper.next(1, 4 + 1);
                int xPos = (int) ((randomX + 1) * TILE_SIZE + TILE_SIZE / 2);;
                Vec2 bossBirthPos = new Vec2(xPos, yPos);
                userData.getGameData().getBossBirthPosList().add(bossBirthPos);
                allBossCol.add(xPos - hitRange.getWidth() / 2);
                allBossCol.add(xPos + hitRange.getWidth() / 2);
            }
        }
        if (existBoss) {
            int minPosition = Integer.MAX_VALUE;
            int maxPosition = Integer.MIN_VALUE;
            for (Integer position : allBossCol) {
                minPosition = Math.min(position, minPosition);
                maxPosition = Math.max(position, maxPosition);
            }
            userData.getGameData().getBossCol().add(minPosition);
            userData.getGameData().getBossCol().add(maxPosition);
        }
    }

    /**
     * 取消,退出
     */
    public KowloonProto.KowloonCancelChapterRespMsg.Builder cancelGame() {
        KowloonProto.KowloonCancelChapterRespMsg.Builder respMsg = KowloonProto.KowloonCancelChapterRespMsg.newBuilder();
        respMsg.setRet(0);
        if (null == userData) {
            return respMsg.setRet(GameErrorCode.E_ERROR_DATA);
        }
        if (userData.getGameData() == null) {
            return respMsg.setRet(GameErrorCode.E_ERROR_DATA);
        }

        // 记录结算日志
        AutoLogMgr.add(new LogKowloonChapterFinish(player.getUserId(), userData.getGameData().getChapterId(), 2));

        KowloonProto.KowloonResultMsg.Builder result = KowloonProto.KowloonResultMsg.newBuilder();
        result.setChapterId(userData.getGameData().getChapterId());
        result.setSectionId(userData.getGameData().getSectionId());
        result.setIsWin(false);
        userData.setGameData(null);
        result.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
        respMsg.setResult(result);
        return respMsg;
    }

    /**
     * 每日重置
     */
    public void resetOneDay() {
        if (userData == null) {
            return;
        }
        long beginTimestamp = DateHelper.getWeekBeginTimestamp();
        if (userData.getSpeedResetTime() < beginTimestamp) {
            userData.setSpeedResetTime(beginTimestamp);
            userData.setSpeedTimes(0);
        }
        long todayZeroTimeStamp = DateHelper.getTodayZeroTimeStamp();
        if (userData.getChallengeResetTime() < todayZeroTimeStamp) {
            userData.setChallengeTimes(0);
            userData.setChallengeResetTime(todayZeroTimeStamp);
        }
        // 同步下用户数据
        syncUserData();
    }


    /**
     * 外部调用
     * 调试用
     */
    public void debug() {

    }

    /**
     * 获取战力
     * @return
     */
    public long getPower() {
        //配置
        KowloonConfig config = KowloonMgr.getConfig();

        // 士气加成
        long addition = 0;
        // 获取当前士气技能
        SkillInfo moraleSkillInfo = KowloonMgr.getKowloonMoraleSkillInfo(userData.getMoraleLevel());
        if (moraleSkillInfo != null) {
            List<Integer> paramList = moraleSkillInfo.getParamList();
            addition += paramList.get(3);
        }

        //遍历选择的角色
        long power = 0;
        for (KowloonHeroData heroData : this.heroDataMap.values()) {
//            if (heroData.getHeroIdx() != -1) {
            KowloonNpcConfig heroConfig = config.getKowloonHeroConfig(heroData.getHeroId(), heroData.getLevel());
            if (heroConfig != null) {
                long resultPower = BigDecimal.valueOf(heroConfig.getPower()).multiply(BigDecimal.valueOf(1000 + addition)).divide(BigDecimal.valueOf(1000), 0, RoundingMode.DOWN).longValue();
                power += resultPower;
            }
//            }
        }
        return power;
    }

    /**
     * 快速过关
     * @param req
     * @return
     */
    public KowloonProto.KowloonFastPassRespMsg.Builder fastPass(KowloonProto.KowloonFastPassReqMsg req) {
        KowloonProto.KowloonFastPassRespMsg.Builder respMsg = KowloonProto.KowloonFastPassRespMsg.newBuilder();
        //判断关卡id是否合法
        if (req.getChapterId() <= this.userData.getChapterId()) {
            respMsg.setRet(GameErrorCode.E_KOWLOON_FAST_PASS_CHAPTER_ID_ERROR);
            return respMsg;
        }
        KowloonConfig config = KowloonMgr.getConfig();
        KowloonMissionRoadConfig missionRoadConfig = config.getKowloonMissionRoadConfig(req.getChapterId());
        if (missionRoadConfig == null) {
            respMsg.setRet(GameErrorCode.E_KOWLOON_CONFIG_NOT_FOUND);
            return respMsg;
        }
        //每日挑战次数是否达到
        if (userData.getChallengeTimes() >= GameConfig.KOWLOON_DAILY_CHALLENGE_TIMES) {
            respMsg.setRet(GameErrorCode.E_KOWLOON_CHALLENGE_TIMES_LIMIT);
            return respMsg;
        }
        //我方战力
        long power = this.getPower();
        //判断战力是否合法
        if (power < missionRoadConfig.getNeedPower()) {
            respMsg.setRet(GameErrorCode.E_KOWLOON_FAST_PASS_POWER_NOT_ENOUGH);
            return respMsg;
        }
        //每日挑战次数 + 1
        userData.setChallengeTimes(userData.getChallengeTimes() + 1);
        //快速过关
        String reward = this.passHandle(req.getChapterId());
        //PB
        KowloonProto.KowloonResultMsg.Builder result = KowloonProto.KowloonResultMsg.newBuilder();
        result.setChapterId(userData.getChapterId());
        result.setSectionId(0);
        result.setIsWin(true);
        result.setUserData(KowloonPb.parseKowloonUserDataTemp(userData));
        result.setReward(reward);
        //返回
        respMsg.setRet(0);
        respMsg.setResult(result);
        return respMsg;
    }

}
